package es

import (
	"bytes"
	"context"
	"errors"
	"net/http"
	"os"
	"path/filepath"

	"github.com/elastic/go-elasticsearch/v9"
	"github.com/elastic/go-elasticsearch/v9/esapi"
	"github.com/samber/do/v2"
	"github.com/spf13/viper"

	"gitee.com/monkeyPP/happy-mall/pkg/log"
)

type Config struct {
	Address []string         `json:"address" mapstructure:"address"`
	Indexes map[string]Index `json:"indexes" mapstructure:"indexes"`
}

type Index struct {
	Name        string `json:"name" mapstructure:"name"`
	MappingPath string `json:"mapping_path" mapstructure:"mapping_path"`
}

// Init 初始化 elasticsearch 客户端
func Init(i do.Injector) (*elasticsearch.Client, error) {
	var esCfg Config
	err := viper.UnmarshalKey("es", &esCfg)
	if err != nil {
		return nil, err
	}

	cfg := elasticsearch.Config{
		Addresses: esCfg.Address,
	}
	client, err := elasticsearch.NewClient(cfg)
	if err != nil {
		panic(err)
	}
	return client, nil
}

// InitIndex 初始化索引
func InitIndex(esClient *elasticsearch.Client, rootDir string) error {
	var esCfg Config
	err := viper.UnmarshalKey("es", &esCfg)
	if err != nil {
		return err
	}

	indexMaps := esCfg.Indexes
	for _, indexMap := range indexMaps {
		indexName := indexMap.Name
		indexMappingPath := indexMap.MappingPath
		existReq := esapi.IndicesExistsRequest{Index: []string{indexName}}
		existsRes, err := existReq.Do(context.Background(), esClient)
		if err != nil {
			log.Errorw("check index error", "index", indexName, "err", err)
			return err
		}
		defer existsRes.Body.Close()

		if existsRes.StatusCode == http.StatusOK {
			log.Infow("index exist", "index", indexName, "exists", existsRes.StatusCode)
			continue
		}

		// 读取 mapping 文件
		mappingData, err := os.ReadFile(filepath.Join(rootDir, "configs", indexMappingPath))
		if err != nil {
			log.Errorw("read index mapping error", "index", indexName, "err", err)
			return err
		}

		// 创建索引
		createReq := esapi.IndicesCreateRequest{
			Index: indexName,
			Body:  bytes.NewReader(mappingData),
		}
		createRes, err := createReq.Do(context.Background(), esClient)
		if err != nil {
			log.Errorw("create index error", "index", indexName, "err", err)
			return err
		}
		defer createRes.Body.Close()

		if createRes.IsError() {
			log.Errorw("create index error", "index", indexName, "err", createRes.String())
			return errors.New(createRes.String())
		}
	}
	return nil
}
